package middleware

import (
	"context"
	"gf_blog_admin/internal/consts"
	"gf_blog_admin/internal/model"
	"gf_blog_admin/internal/service"
	"gf_blog_admin/utility/casbinPolicy"
	"gf_blog_admin/utility/errors"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"strings"
)

// JwtAuth token处理中间件
func (s *sMiddleware) JwtAuth(r *ghttp.Request) {
	var (
		ctx         = r.GetCtx()
		tokenString = r.Header.Get("Authorization")
		handler     = r.GetServeHandler()
	)

	// 检查是否有noAuth元数据，如果有且值为true，则跳过验证
	noAuth := handler.GetMetaTag("noAuth")
	if noAuth == "true" {
		r.Middleware.Next()
		return
	}

	// Get token from Authorization header
	if tokenString == "" {
		r.SetError(gerror.NewCode(errors.CodeNotAuthorized))
		return
	}

	// Remove 'Bearer ' prefix if present
	if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
		tokenString = tokenString[7:]
	}

	// Parse and validate the token
	claims, err := service.Token().ParseTokenClaims(ctx, tokenString)
	if err != nil {
		r.SetError(gerror.NewCode(errors.CodeInvalidToken))
		return
	}

	if err = service.Token().IsValid(ctx, claims.UserId, claims.Device, tokenString); err != nil {
		r.SetError(err)
		return
	}

	// Store user in context for later use
	r.SetCtxVar(consts.CtxUser, claims)
	r.SetCtxVar(consts.CtxUId, claims.UserId)
	r.Middleware.Next()
}

// Permission 权限处理中间件
func (s *sMiddleware) Permission(r *ghttp.Request) {
	var (
		ctx     = r.GetCtx()
		handler = r.GetServeHandler()
	)

	// 检查是否有noCan元数据，如果有且值为true，则跳过验证
	noCan := handler.GetMetaTag("noCan")
	if noCan == "true" {
		r.Middleware.Next()
		return
	}

	// 验证路由访问权限
	rule := handler.GetMetaTag("can")
	if rule == "" {
		rule = strings.Replace(handler.Handler.Router.Uri, "/api", "", 1)
	}
	if !checkPermission(ctx, rule) {
		r.SetError(gerror.NewCode(errors.CodeForbidden, "无访问权限"))
		return
	}

	r.Middleware.Next()
}

// 验证权限
func checkPermission(ctx context.Context, rule string) bool {
	user := ctx.Value(consts.CtxUser).(*model.JwtClaims)
	if user == nil {
		return false
	}

	if user.IsSuper || user.Role == consts.SuperRole {
		return true
	}

	has, err := casbinPolicy.Enforcer.Enforce(user.Role, rule, "all")
	if err != nil {
		return false
	}
	return has
}
